﻿using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Core
{
    public class SendMessenger
    {
        #region WM_MESSAGES

        protected class WMmessages
        {
            public const int WM_NULL = 0x000;
            public const int WM_CREATE = 0x001;
            public const int WM_DESTROY = 0x002;
            public const int WM_MOVE = 0x003;
            public const int WM_SIZE = 0x005;
            public const int WM_ACTIVATE = 0x006;
            public const int WM_SETFOCUS = 0x007;
            public const int WM_KILLFOCUS = 0x008;
            public const int WM_ENABLE = 0x00A;
            public const int WM_SETREDRAW = 0x00B;
            public const int WM_SETTEXT = 0x00C;
            public const int WM_GETTEXT = 0x00D;
            public const int WM_GETTEXTLENGTH = 0x00E;
            public const int WM_PAINT = 0x00F;
            public const int WM_CLOSE = 0x010;
            public const int WM_QUERYENDSESSION = 0x011;
            public const int WM_QUIT = 0x012;
            public const int WM_QUERYOPEN = 0x013;
            public const int WM_ERASEBKGND = 0x014;
            public const int WM_SYSCOLORCHANGE = 0x015;
            public const int WM_ENDSESSION = 0x016;
            public const int WM_SHOWWINDOW = 0x018;
            public const int WM_WININICHANGE = 0x01A;
            public const int WM_DEVMODECHANGE = 0x01B;
            public const int WM_ACTIVATEAPP = 0x01C;
            public const int WM_FONTCHANGE = 0x01D;
            public const int WM_TIMECHANGE = 0x01E;
            public const int WM_CANCELMODE = 0x01F;
            public const int WM_SETCURSOR = 0x020;
            public const int WM_MOUSEACTIVATE = 0x021;
            public const int WM_CHILDACTIVATE = 0x022;
            public const int WM_QUEUESYNC = 0x023;
            public const int WM_GETMINMAXINFO = 0x024;
            public const int WM_PAINTICON = 0x026;
            public const int WM_ICONERASEBKGND = 0x027;
            public const int WM_NEXTDLGCTL = 0x028;
            public const int WM_SPOOLERSTATUS = 0x02A;
            public const int WM_DRAWITEM = 0x02B;
            public const int WM_MEASUREITEM = 0x02C;
            public const int WM_DELETEITEM = 0x02D;
            public const int WM_VKEYTOITEM = 0x02E;
            public const int WM_CHARTOITEM = 0x02F;
            public const int WM_SETFONT = 0x030;
            public const int WM_GETFONT = 0x031;
            public const int WM_SETHOTKEY = 0x032;
            public const int WM_GETHOTKEY = 0x033;
            public const int WM_QUERYDRAGICON = 0x037;
            public const int WM_COMPAREITEM = 0x039;
            public const int WM_COMPACTING = 0x041;
            public const int WM_COMMNOTIFY = 0x044; /* no longer suported */
            public const int WM_WINDOWPOSCHANGING = 0x046;
            public const int WM_WINDOWPOSCHANGED = 0x047;
            public const int WM_POWER = 0x048;
            public const int WM_COPYDATA = 0x04A;
            public const int WM_CANCELJOURNAL = 0x04B;
            public const int WM_USER = 0x400;
            public const int WM_NOTIFY = 0x04E;
            public const int WM_INPUTLANGCHANGEREQUEST = 0x050;
            public const int WM_INPUTLANGCHANGE = 0x051;
            public const int WM_TCARD = 0x052;
            public const int WM_HELP = 0x053;
            public const int WM_USERCHANGED = 0x054;
            public const int WM_NOTIFYFORMAT = 0x055;
            public const int WM_CONTEXTMENU = 0x07B;
            public const int WM_STYLECHANGING = 0x07C;
            public const int WM_STYLECHANGED = 0x07D;
            public const int WM_DISPLAYCHANGE = 0x07E;
            public const int WM_GETICON = 0x07F;
            public const int WM_SETICON = 0x080;
            public const int WM_NCCREATE = 0x081;
            public const int WM_NCDESTROY = 0x082;
            public const int WM_NCCALCSIZE = 0x083;
            public const int WM_NCHITTEST = 0x084;
            public const int WM_NCPAINT = 0x085;
            public const int WM_NCACTIVATE = 0x086;
            public const int WM_GETDLGCODE = 0x087;
            public const int WM_SYNCPAINT = 0x088;
            public const int WM_NCMOUSEMOVE = 0x0A0;
            public const int WM_NCLBUTTONDOWN = 0x0A1;
            public const int WM_NCLBUTTONUP = 0x0A2;
            public const int WM_NCLBUTTONDBLCLK = 0x0A3;
            public const int WM_NCRBUTTONDOWN = 0x0A4;
            public const int WM_NCRBUTTONUP = 0x0A5;
            public const int WM_NCRBUTTONDBLCLK = 0x0A6;
            public const int WM_NCMBUTTONDOWN = 0x0A7;
            public const int WM_NCMBUTTONUP = 0x0A8;
            public const int WM_NCMBUTTONDBLCLK = 0x0A9;
            public const int WM_NCXBUTTONDOWN = 0x0AB;
            public const int WM_NCXBUTTONUP = 0x0AC;
            public const int WM_NCXBUTTONDBLCLK = 0x0AD;
            public const int WM_INPUT = 0x0FF;
            public const int WM_KEYFIRST = 0x100;
            public const int WM_KEYDOWN = 0x100;
            public const int WM_KEYUP = 0x101;
            public const int WM_CHAR = 0x102;
            public const int WM_DEADCHAR = 0x103;
            public const int WM_SYSKEYDOWN = 0x104;
            public const int WM_SYSKEYUP = 0x105;
            public const int WM_SYSCHAR = 0x106;
            public const int WM_SYSDEADCHAR = 0x107;
            public const int WM_UNICHAR = 0x109;
            public const int WM_KEYLAST = 0x109;
            public const int WM_IME_STARTCOMPOSITION = 0x10D;
            public const int WM_IME_ENDCOMPOSITION = 0x10E;
            public const int WM_IME_COMPOSITION = 0x10F;
            public const int WM_IME_KEYLAST = 0x10F;
            public const int WM_INITDIALOG = 0x110;
            public const int WM_COMMAND = 0x111;
            public const int WM_SYSCOMMAND = 0x112;
            public const int WM_TIMER = 0x113;
            public const int WM_HSCROLL = 0x114;
            public const int WM_VSCROLL = 0x115;
            public const int WM_INITMENU = 0x116;
            public const int WM_INITMENUPOPUP = 0x117;
            public const int WM_MENUSELECT = 0x11F;
            public const int WM_MENUCHAR = 0x120;
            public const int WM_ENTERIDLE = 0x121;
            public const int WM_MENURBUTTONUP = 0x122;
            public const int WM_MENUDRAG = 0x123;
            public const int WM_MENUGETOBJECT = 0x124;
            public const int WM_UNINITMENUPOPUP = 0x125;
            public const int WM_MENUCOMMAND = 0x126;
            public const int WM_CHANGEUISTATE = 0x127;
            public const int WM_UPDATEUISTATE = 0x128;
            public const int WM_QUERYUISTATE = 0x129;
            public const int WM_CTLCOLORMSGBOX = 0x132;
            public const int WM_CTLCOLOREDIT = 0x133;
            public const int WM_CTLCOLORLISTBOX = 0x134;
            public const int WM_CTLCOLORBTN = 0x135;
            public const int WM_CTLCOLORDLG = 0x136;
            public const int WM_CTLCOLORSCROLLBAR = 0x137;
            public const int WM_CTLCOLORSTATIC = 0x138;
            public const int MN_GETHMENU = 0x1E1;
            public const int WM_MOUSEFIRST = 0x200;
            public const int WM_MOUSEMOVE = 0x200;
            public const int WM_LBUTTONDOWN = 0x201;
            public const int WM_LBUTTONUP = 0x202;
            public const int WM_LBUTTONDBLCLK = 0x203;
            public const int WM_RBUTTONDOWN = 0x204;
            public const int WM_RBUTTONUP = 0x205;
            public const int WM_RBUTTONDBLCLK = 0x206;
            public const int WM_MBUTTONDOWN = 0x207;
            public const int WM_MBUTTONUP = 0x208;
            public const int WM_MBUTTONDBLCLK = 0x209;
            public const int WM_MOUSEWHEEL = 0x20A;
            public const int WM_XBUTTONDOWN = 0x20B;
            public const int WM_XBUTTONUP = 0x20C;
            public const int WM_XBUTTONDBLCLK = 0x20D;
            public const int WM_MOUSELAST = 0x20A;
            public const int WM_PARENTNOTIFY = 0x210;
            public const int WM_ENTERMENULOOP = 0x211;
            public const int WM_EXITMENULOOP = 0x212;
            public const int WM_NEXTMENU = 0x213;
            public const int WM_SIZING = 0x214;
            public const int WM_CAPTURECHANGED = 0x215;
            public const int WM_MOVING = 0x216;
            public const int WM_POWERBROADCAST = 0x218;
            public const int WM_DEVICECHANGE = 0x219;
            public const int WM_MDICREATE = 0x220;
            public const int WM_MDIDESTROY = 0x221;
            public const int WM_MDIACTIVATE = 0x222;
            public const int WM_MDIRESTORE = 0x223;
            public const int WM_MDINEXT = 0x224;
            public const int WM_MDIMAXIMIZE = 0x225;
            public const int WM_MDITILE = 0x226;
            public const int WM_MDICASCADE = 0x227;
            public const int WM_MDIICONARRANGE = 0x228;
            public const int WM_MDIGETACTIVE = 0x229;
            public const int WM_MDISETMENU = 0x230;
            public const int WM_ENTERSIZEMOVE = 0x231;
            public const int WM_EXITSIZEMOVE = 0x232;
            public const int WM_DROPFILES = 0x233;
            public const int WM_MDIREFRESHMENU = 0x234;
            public const int WM_IME_SETCONTEXT = 0x281;
            public const int WM_IME_NOTIFY = 0x282;
            public const int WM_IME_CONTROL = 0x283;
            public const int WM_IME_COMPOSITIONFULL = 0x284;
            public const int WM_IME_SELECT = 0x285;
            public const int WM_IME_CHAR = 0x286;
            public const int WM_IME_REQUEST = 0x288;
            public const int WM_IME_KEYDOWN = 0x290;
            public const int WM_IME_KEYUP = 0x291;
            public const int WM_MOUSEHOVER = 0x2A1;
            public const int WM_MOUSELEAVE = 0x2A3;
            public const int WM_NCMOUSEHOVER = 0x2A0;
            public const int WM_NCMOUSELEAVE = 0x2A2;
            public const int WM_WTSSESSION_CHANGE = 0x2B1;
            public const int WM_TABLET_FIRST = 0x2c0;
            public const int WM_TABLET_LAST = 0x2df;
            public const int WM_CUT = 0x300;
            public const int WM_COPY = 0x301;
            public const int WM_PASTE = 0x302;
            public const int WM_CLEAR = 0x303;
            public const int WM_UNDO = 0x304;
            public const int WM_RENDERFORMAT = 0x305;
            public const int WM_RENDERALLFORMATS = 0x306;
            public const int WM_DESTROYCLIPBOARD = 0x307;
            public const int WM_DRAWCLIPBOARD = 0x308;
            public const int WM_PAINTCLIPBOARD = 0x309;
            public const int WM_VSCROLLCLIPBOARD = 0x30A;
            public const int WM_SIZECLIPBOARD = 0x30B;
            public const int WM_ASKCBFORMATNAME = 0x30C;
            public const int WM_CHANGECBCHAIN = 0x30D;
            public const int WM_HSCROLLCLIPBOARD = 0x30E;
            public const int WM_QUERYNEWPALETTE = 0x30F;
            public const int WM_PALETTEISCHANGING = 0x310;
            public const int WM_PALETTECHANGED = 0x311;
            public const int WM_HOTKEY = 0x312;
            public const int WM_PRINT = 0x317;
            public const int WM_PRINTCLIENT = 0x318;
            public const int WM_APPCOMMAND = 0x319;
            public const int WM_THEMECHANGED = 0x31A;
            public const int WM_HANDHELDFIRST = 0x358;
            public const int WM_HANDHELDLAST = 0x35F;
            public const int WM_AFXFIRST = 0x360;
            public const int WM_AFXLAST = 0x37F;
            public const int WM_PENWINFIRST = 0x380;
            public const int WM_PENWINLAST = 0x38F;
        }

        #endregion

        #region MK_Controls
        /*
        * Key State Masks for Mouse Messages
        */
        protected class MK_Controls
        {
            public const int MK_LBUTTON = 0x0001;
            public const int MK_RBUTTON = 0x0002;
            public const int MK_SHIFT = 0x0004;
            public const int MK_CONTROL = 0x0008;
            public const int MK_MBUTTON = 0x0010;
        }

        #endregion

        #region Virtual Keys

        protected enum VK : int
        {
            VK_LBUTTON = 0x01,   //Left mouse button
            VK_RBUTTON = 0x02,   //Right mouse button
            VK_CANCEL = 0x03,   //Control-break processing
            VK_MBUTTON = 0x04, //Middle mouse button (three-button mouse)
            VK_BACK = 0x08,   //BACKSPACE key
            VK_TAB = 0x09,   //TAB key
            VK_CLEAR = 0x0C,     //CLEAR key
            VK_RETURN = 0x0D,   //ENTER key
            VK_SHIFT = 0x10,   //SHIFT key
            VK_CONTROL = 0x11,  //CTRL key
            VK_MENU = 0x12,    //ALT key
            VK_PAUSE = 0x13,  //PAUSE key
            VK_CAPITAL = 0x14,   //CAPS LOCK key
            VK_ESCAPE = 0x1B,   //ESC key
            VK_SPACE = 0x20,   //SPACEBAR
            VK_PRIOR = 0x21,   //PAGE UP key
            VK_NEXT = 0x22,   //PAGE DOWN key
            VK_END = 0x23,   //END key
            VK_HOME = 0x24,   //HOME key
            VK_LEFT = 0x25,  //LEFT ARROW key
            VK_UP = 0x26,   //UP ARROW key
            VK_RIGHT = 0x27,   //RIGHT ARROW key
            VK_DOWN = 0x28,   //DOWN ARROW key
            VK_SELECT = 0x29,   //SELECT key
            VK_PRINT = 0x2A,   //PRINT key
            VK_EXECUTE = 0x2B,   //EXECUTE key
            VK_SNAPSHOT = 0x2C,   //PRINT SCREEN key
            VK_INSERT = 0x2D,   //INS key
            VK_DELETE = 0x2E,   //DEL key
            VK_HELP = 0x2F,   //HELP key
            VK_0 = 0x30,   //0 key
            VK_1 = 0x31,   //1 key
            VK_2 = 0x32,   //2 key
            VK_3 = 0x33,   //3 key
            VK_4 = 0x34,   //4 key
            VK_5 = 0x35,   //5 key
            VK_6 = 0x36,   //6 key
            VK_7 = 0x37,   //7 key
            VK_8 = 0x38,   //8 key
            VK_9 = 0x39,   //9 key
            VK_A = 0x41,   //A key
            VK_B = 0x42,   //B key
            VK_C = 0x43,   //C key
            VK_D = 0x44,   //D key
            VK_E = 0x45,   //E key
            VK_F = 0x46,   //F key
            VK_G = 0x47,   //G key
            VK_H = 0x48,   //H key
            VK_I = 0x49,   //I key
            VK_J = 0x4A,   //J key
            VK_K = 0x4B,   //K key
            VK_L = 0x4C,   //L key
            VK_M = 0x4D,   //M key
            VK_N = 0x4E,   //N key
            VK_O = 0x4F,   //O key
            VK_P = 0x50,   //P key
            VK_Q = 0x51,   //Q key
            VK_R = 0x52,   //R key
            VK_S = 0x53,   //S key
            VK_T = 0x54,   //T key
            VK_U = 0x55,   //U key
            VK_V = 0x56,   //V key
            VK_W = 0x57,   //W key
            VK_X = 0x58,   //X key
            VK_Y = 0x59,   //Y key
            VK_Z = 0x5A,   //Z key
            VK_NUMPAD0 = 0x60,   //Numeric keypad 0 key
            VK_NUMPAD1 = 0x61,   //Numeric keypad 1 key
            VK_NUMPAD2 = 0x62,   //Numeric keypad 2 key
            VK_NUMPAD3 = 0x63,   //Numeric keypad 3 key
            VK_NUMPAD4 = 0x64,   //Numeric keypad 4 key
            VK_NUMPAD5 = 0x65,   //Numeric keypad 5 key
            VK_NUMPAD6 = 0x66,   //Numeric keypad 6 key
            VK_NUMPAD7 = 0x67,   //Numeric keypad 7 key
            VK_NUMPAD8 = 0x68,   //Numeric keypad 8 key
            VK_NUMPAD9 = 0x69,   //Numeric keypad 9 key
            VK_SEPARATOR = 0x6C,   //Separator key
            VK_SUBTRACT = 0x6D,   //Subtract key
            VK_DECIMAL = 0x6E,   //Decimal key
            VK_DIVIDE = 0x6F,   //Divide key
            VK_F1 = 0x70,   //F1 key
            VK_F2 = 0x71,   //F2 key
            VK_F3 = 0x72,   //F3 key
            VK_F4 = 0x73,   //F4 key
            VK_F5 = 0x74,   //F5 key
            VK_F6 = 0x75,   //F6 key
            VK_F7 = 0x76,   //F7 key
            VK_F8 = 0x77,   //F8 key
            VK_F9 = 0x78,   //F9 key
            VK_F10 = 0x79,  //F10 key
            VK_F11 = 0x7A,  //F11 key
            VK_F12 = 0x7B,  //F12 key
            VK_SCROLL = 0x91,   //SCROLL LOCK key
            VK_LSHIFT = 0xA0,   //Left SHIFT key
            VK_RSHIFT = 0xA1,   //Right SHIFT key
            VK_LCONTROL = 0xA2, //Left CONTROL key
            VK_RCONTROL = 0xA3, //Right CONTROL key
            VK_LMENU = 0xA4,    //Left MENU key
            VK_RMENU = 0xA5,    //Right MENU key
            VK_PLAY = 0xFA,    //Play key
            VK_ZOOM = 0xFB,   //Zoom key
        }

        #endregion

        #region ShowWindow Params

        protected class SW
        {
            public const int SW_HIDE = 0;
            public const int SW_SHOWNORMAL = 1;
            public const int SW_SHOWMINIMIZED = 2;
            public const int SW_SHOWMAXIMIZED = 3;
            public const int SW_SHOWNOACTIVATE = 4;
            public const int SW_SHOW = 5;
            public const int SW_MINIMIZE = 6;
            public const int SW_SHOWMINNOACTIVE = 7;
            public const int SW_SHOWNA = 8;
            public const int SW_RESTORE = 9;
            public const int SW_SHOWDEFAULT = 10;
            public const int SW_FORCEMINIMIZE = 11;
        }

        #endregion

        #region Invokes

        [DllImport("User32.dll")]
        private static extern int RegisterWindowMessage(string lpString);

        //For use with WM_COPYDATA and COPYDATASTRUCT
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
        //overloads for various actions
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, StringBuilder lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, String lParam);
        //
        [DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool PostMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

        #endregion

        protected IntPtr hWnd;

        protected SendMessenger(IntPtr windowhandle)
        {
            this.hWnd = windowhandle;
        }

        protected bool BringAppToFront()
        {
            return ShowWindow(this.hWnd, SW.SW_RESTORE);
        }

        protected IntPtr SendWMText(string msg)
        {
            if (hWnd != IntPtr.Zero)
                return SendMessage(this.hWnd, WMmessages.WM_SETTEXT, IntPtr.Zero, msg);
            return IntPtr.Zero;
        }

        protected IntPtr MouseMove(int x, int y)
        {
            if (hWnd != IntPtr.Zero)
                return SendMessage(this.hWnd, WMmessages.WM_MOUSEMOVE, IntPtr.Zero, MakeLParam(x, y));
            return IntPtr.Zero;
        }

        protected IntPtr SendText(string msg, int delay)
        {
            IntPtr result = IntPtr.Zero;
            if (hWnd != IntPtr.Zero)
            {
                for (int index = 0; index < msg.Length; index++)
                {
                    result = SendMessage(this.hWnd, WMmessages.WM_CHAR, (IntPtr)msg[index], IntPtr.Zero);
                    System.Threading.Thread.Sleep(delay);
                }
            }
            return result;
        }

        protected IntPtr SendKey(VK vkey, int delay)
        {
            IntPtr result = IntPtr.Zero;
            if (hWnd != IntPtr.Zero)
            {
                result = SendMessage(this.hWnd, WMmessages.WM_KEYDOWN, (IntPtr)vkey, IntPtr.Zero);
                System.Threading.Thread.Sleep(delay);
                result = SendMessage(this.hWnd, WMmessages.WM_KEYUP, (IntPtr)vkey, IntPtr.Zero);
                System.Threading.Thread.Sleep(delay);
            }
            return result;
        }

        protected IntPtr SendLeftMouseClick(int x, int y, int delay)
        {
            IntPtr result = IntPtr.Zero;
            if (hWnd != IntPtr.Zero)
            {
                MouseMove(x, y);
                System.Threading.Thread.Sleep(delay);
                result = SendMessage(this.hWnd, WMmessages.WM_LBUTTONDOWN, (IntPtr)MK_Controls.MK_LBUTTON, MakeLParam(x, y));
                System.Threading.Thread.Sleep(delay);
                result = SendMessage(this.hWnd, WMmessages.WM_LBUTTONUP, (IntPtr)MK_Controls.MK_LBUTTON, MakeLParam(x, y));
                System.Threading.Thread.Sleep(delay);
            }
            return result;
        }

        protected IntPtr SendCopyDataMessage(int wParam, string msg)
        {
            if (hWnd != IntPtr.Zero)
            {
                byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);
                int len = sarr.Length;
                COPYDATASTRUCT cds;
                cds.dwData = (IntPtr)wParam;
                cds.lpData = msg;
                cds.cbData = len + 1;
                return SendMessage(this.hWnd, WMmessages.WM_COPYDATA, (IntPtr)wParam, ref cds);
            }
            return IntPtr.Zero;
        }

        private IntPtr MakeLParam(int LoWord, int HiWord)
        {
            return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
        }
    }
}
